package mysql

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	"time"

	"github.com/cloudwego/hertz/pkg/common/hlog"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

const dbConfig = "timeout=5s&charset=utf8&parseTime=True&loc=Local"
const gormLogLevel = logger.Info
const gormMaxIdleConns = 100
const gormMaxOpenConns = 500
const gormMaxLifetime = time.Hour * 4

func Init(ip string, port int, dbname string, username string, password string) error {
	mysqlConfig := mysql.Config{
		DSN:                       DSN(ip, port, dbname, username, password), // DSN data source name
		DefaultStringSize:         255,                                       // string 类型字段的默认长度
		DisableDatetimePrecision:  true,                                      // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,                                      // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,                                      // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false,                                     // 根据当前 MySQL 版本自动配置
	}

	hlog.Infof("开始连接数据库,%s", mysqlConfig.DSN)

	//连接数据库
	dbConfig := mysql.New(mysqlConfig)
	db, err := gorm.Open(dbConfig, GormConfig())
	if err != nil {
		return fmt.Errorf("gorm.Open失败,%v", err)
	}
	hlog.Infof("数据库连接成功")
	sqlDB, _ := db.DB()
	hlog.Infof("开始执行ping命令")
	if err := sqlDB.Ping(); err != nil {
		return fmt.Errorf("sqlDB.Ping失败,%v", err)
	}
	hlog.Infof("ping执行成功")
	// 设置默认值
	Options(sqlDB, 
		WithMaxIdelConns(gormMaxIdleConns), 
		WithMaxOpenConns(gormMaxOpenConns), 
		WithMaxLifeTime(gormMaxLifetime))
	
	setGlobalDB(db)
	return nil
}

func DSN(ip string, port int, dbname string, user string, password string) string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?%s", user, password, ip, port, dbname, dbConfig)
}

func GormConfig() *gorm.Config {
	//禁用外键约束
	config := &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,
	}

	//NewWriter 对log.New函数的再次封装，从而实现是否通过zap打印日志
	_default := logger.New(NewWriter(log.New(os.Stdout, "\r\n", log.LstdFlags)), logger.Config{
		SlowThreshold: 200 * time.Millisecond,
		LogLevel:      logger.Warn,
		Colorful:      false,
	})

	//设置logger的日志输出等级
	config.Logger = _default.LogMode(gormLogLevel)
	return config
}

type writer struct {
	logger.Writer
}

// NewWriter writer 构造函数
func NewWriter(w logger.Writer) *writer {
	return &writer{Writer: w}
}

// Printf 格式化打印日志
func (w *writer) Printf(message string, data ...interface{}) {
	hlog.Info(fmt.Sprintf(message+"\n", data...))
}

// Option设计模式封装mysql的额外配置
type Option func(m *sql.DB)

func WithMaxIdelConns(idle int) Option {
	return func(m *sql.DB) {
		if idle == 0 {
			return
		}
		m.SetMaxIdleConns(idle)
	}
}

func WithMaxOpenConns(open int) Option {
	return func(m *sql.DB) {
		if open == 0 {
			return
		}
		m.SetMaxOpenConns(open)
	}
}

func WithMaxLifeTime(t time.Duration) Option {
	return func(m *sql.DB) {
		if t == 0 {
			return
		}
		m.SetConnMaxLifetime(t)
	}
}

func Options(m *sql.DB, opts ...Option) {
	for _, opt := range opts {
		opt(m)
	}
}

// func prometheusPlugin() gorm.Plugin {
// 	prometheus.New(prometheus.Config{
// 		DBName:          "db1",                       // 使用 `DBName` 作为指标 label
// 		RefreshInterval: 15,                          // 指标刷新频率（默认为 15 秒）
// 		PushAddr:        "prometheus pusher address", // 如果配置了 `PushAddr`，则推送指标
// 		StartServer:     true,                        // 启用一个 http 服务来暴露指标
// 		HTTPServerPort:  8080,                        // 配置 http 服务监听端口，默认端口为 8080 （如果您配置了多个，只有第一个 `HTTPServerPort` 会被使用）
// 		MetricsCollector: []prometheus.MetricsCollector{
// 			&prometheus.MySQL{
// 				Prefix:        "gorm_mysql_stats_",
// 				Interval:      15,
// 				VariableNames: []string{"Threads_running"},
// 			},
// 		}, // 用户自定义指标
// 	})
// }
